package xj.graph2d.tools;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Observer;

import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.DrawShapeFactory;
import xj.graph2d.SelfLoop;
import xj.graph2d.GraphEdgeBase;
import xj.graph2d.shapes.OrthogonalLineShape;
import xj.graph2d.shapes.PolyCurveShape;
import xj.graph2d.shapes.PolyShape;
import xj.graph2d.shapes.GraphEdgeShape;
import xj.util.gui.Point2DFloat;

public class TwoEndsPolyLineDrawTool 
  extends TwoEndsDrawTool {

  public TwoEndsPolyLineDrawTool(PolyShape shape) {
    this(shape, DrawShapeConstants.USE_SYSTEM_DRAW_ATTR, false, null);
  }

  public TwoEndsPolyLineDrawTool(PolyShape shape, 
				 int cloneDrawAttrMode) {
    this(shape, cloneDrawAttrMode, false, null);
  }

  public TwoEndsPolyLineDrawTool(PolyShape shape, 
				 int cloneDrawAttrMode,
				 String shapeKey) {
    this(shape, cloneDrawAttrMode, false, shapeKey);
  }

  public TwoEndsPolyLineDrawTool(PolyShape shape, 
				 int cloneDrawAttrMode,
				 boolean reverseEnds, 
				 String shapeKey) {
    super(shape, cloneDrawAttrMode, shapeKey);
    this.polyline = shape;
    // outline = (PolyShape) DrawShapeFactory.cloneDrawShape(shape,
    // view, cloneDrawAttrMode);
  }

  @Override
  public void mouseLButtonPressed(Observer observer, Point p, int modifiers) {
    mouseButtonDown = true;
    start(observer);
    if (polyline != null && view != null) {
      Graphics2D g2 = canvas.getGraphics2D();
      canvas.setTransform(g2);
      DrawShape selected = doc.getSelectedShape();
      doc.setSelectedShape(null);
      canvas.repaintShape(selected);
      canvas.setEditingMode(true);
      prev = view.physicalToVirtual(p);
      float x = (float) prev.getX();
      float y = (float) prev.getY();
      start = new Point2DFloat(x, y);
      if (cloneDrawAttrMode == USE_SYSTEM_DRAW_ATTR || 
	  cloneDrawAttrMode == CLONE_SYSTEM_DRAW_ATTR) {
	polyline.setDrawAttr(view.getDrawAttr());
      }
      checkSelfLoop();

      g2.setXORMode(view.getBackgroundColor());
      // polyline.copyTo(outline);
      // polyline.copyPointsTo(outline);

      outline = (PolyShape) DrawShapeFactory.cloneDrawShape(shape, view,
								cloneDrawAttrMode);

      adjustShape(outline, x, y, x, y);
      outline.drawShape(g2);
      g2.setPaintMode();
      g2.dispose();
    }
  }

  @Override
  public void mouseDragged(Observer observer, Point p, int modifiers) {
    if (mouseButtonDown && 
	shape != null && 
	start != null && 
	view != null) {

      if (debug) {
	System.out.println("TwoEndsPolyLineDrawTool.mouseDraged()");
      }

      displayLocation(p);
      if (shapeKey != null) {
	view.displayHelpMessage(shapeKey + MSGKEY_2);
      }

      Graphics2D g2 = canvas.getGraphics2D();
      canvas.setTransform(g2);
      Point2D cur = view.physicalToVirtual(p);
      g2.setXORMode(view.getBackgroundColor());
      outline.drawShape(g2);

      float x0, y0, x1, y1;
      if (reverseEnds) { 
	x1 = (float) start.getX();
	y1 = (float) start.getY();
	x0 = (float) cur.getX();
	y0 = (float) cur.getY();
      } else { 
	x0 = (float) start.getX();
	y0 = (float) start.getY();
	x1 = (float) cur.getX();
	y1 = (float) cur.getY();
      }

      if (debug) {
	System.out.println("TwoEndsPolyLineDrawTool.mouseDraged()" + " x0="
			   + x0 + " y0=" + y0 + " x1=" + x1 + " y1=" + y1);
      }

      polyline.copyPointsTo(outline);
      adjustShape(outline, x0, y0, x1, y1);
      outline.drawShape(g2);
      g2.setPaintMode();
      prev = cur;
      g2.dispose();
    }
  }

  @Override
  protected void adjustShape(DrawShape shape, 
			     float x1, float y1, 
			     float x2, float y2) {
    if (shape instanceof PolyShape) { 
      PolyShape pline = (PolyShape) shape; 
      pline.scaleFirstLast(x1, y1, x2, y2);

      if (pline instanceof GraphEdgeShape) {
	GraphEdgeShape edge = (GraphEdgeShape) pline; 
	GraphEdgeBase es = edge.getEdgeShape(); 
	if (es instanceof PolyShape) { 
	  PolyShape pshape = (PolyShape) es;
	  if (pshape instanceof SelfLoop) {
	    edge.adjustDirection(src0 != null ? src0.getBounds() : null, x1, y1, x2, y2);
	    edge.adjustSelfLoop();
	  }
	  
	  if (pshape instanceof PolyCurveShape) {
	    edge.adjustControlPoints();
	  } else if (pshape instanceof OrthogonalLineShape) {
	    edge.normalizePoints();
	  }
	}
      } else { 
	if (pline instanceof SelfLoop) {
	  SelfLoop sloop = (SelfLoop) pline;
	  sloop.adjustDirection(src0 != null ? src0.getBounds() : null, x1, y1, x2, y2);
	  sloop.adjustSelfLoop();
	}

	if (pline instanceof PolyCurveShape) {
	  PolyCurveShape curve = (PolyCurveShape) pline;
	  curve.adjustControlPoints();
	} else if (pline instanceof OrthogonalLineShape) {
	  OrthogonalLineShape oline = (OrthogonalLineShape) pline;
	  oline.normalizePoints();
	}
      }
    } else if (shape != null) {
      shape.setEnds(x1, y1, x2, y2);
    }
    
  }

  protected PolyShape polyline, outline;

  protected static final boolean debug = false;

}
